<?php


namespace App\Service;


use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Qiniu\Auth;
use Qiniu\Storage\UploadManager;

class BaiduNlp
{
    // 百度自然语言处理

    // 提交审核地址前缀
    protected $preUrl    = 'https://aip.baidubce.com/rpc/2.0';
    protected $error;

    //   百度应用：财通社（财通社只有相似度对比）
    /*protected $appId     = '38931600';
    protected $APIKey    = 'x70nhWiW2TlhbNWFFA0Bs2XT';
    protected $SecretKey = 'uF4kHcOs0QU7dCXC7Cm5pmiKZECGv4Zk';*/


    //   百度应用：深蓝汇（深蓝汇可以有所有接口）
    protected $appId     = '62236434';
    protected $APIKey    = 'HoJmoBRoQB0j1WPpUMH6M7BZ';
    protected $SecretKey = 'GShXa5jNeHS9blRh5sxd3fVSutjsJEio';

    // 初始化操作
    public function __construct() { }

    // 获取错误信息
    public function getError()
    {
        return $this->error;
    }

    // 短文本相似度
    public function short($text1, $text2)
    {
        // 判断长度
        if(strlen($text1) > 500){
            return $this->return_false('第一个字符串过长！');
        }
        if(strlen($text2) > 500){
            return $this->return_false('第二个字符串过长！');
        }
        // 执行验证
        $url  = '/nlp/v2/simnet';
        $data = ['text_1' => $text1, 'text_2' => $text2, 'model' => 'ERNIE',];
        $res  = $this->request($url, $data);

        return $res;
    }

    // 设置百度应用信息
    public function appInfo($appId, $APIKey, $SecretKey)
    {
        $this->appId     = $appId;
        $this->APIKey    = $APIKey;
        $this->SecretKey = $SecretKey;
    }


    // 获取token 有效期为30天
    public function getToken()
    {
        // 是否有缓存
        $cookie_name  = $this->appId.'baidu_nlp_access_token';
        $access_token = Cache::get($cookie_name);
        if($access_token){
            return $access_token;
        }

        // 如果没有缓存 则会去百度获取
        //$AppID、$APIKey、$SecretKey
        $APIKey    = $this->APIKey;
        $SecretKey = $this->SecretKey;
        // 执行请求 获取 access_token
        $url  = "https://aip.baidubce.com/oauth/2.0/token?client_id=".$APIKey."&client_secret=".$SecretKey."&grant_type=client_credentials";
        $url  = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=".$APIKey."&client_secret=".$SecretKey;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_TIMEOUT, 30);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Accept: application/json']);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 要求结果为字符串且输出到屏幕上

        $response = curl_exec($curl);
        curl_close($curl);

        // 不知道是不是需要只有处理
        $response = json_decode($response, true);
        // 是否成功
        $error = $response['error'] ?? '';
        if(empty($error)){
            $access_token = $response['access_token'] ?? '';
            $expires_in   = $response['expires_in'] ?? '';
            // 保存为缓存
            // 因为请求回来，需要花费时间，所以缓存时间应该比过期时间少一点
            Cache::add($cookie_name, $access_token, $expires_in - 20);

            return $access_token;
        }

        return $response;
    }

    // 情感趋向分析
    public function sentiment($text)
    {
        if(mb_strlen($text) > 500){
            return $this->return_false('字符串过长！');
        }
        // 执行验证
        $url  = '/nlp/v1/sentiment_classify';
        $data = ['text' => $text,];
        $res  = $this->request($url, $data);

        return $res;
    }


    // 请求操作
    protected function request($url = '', $param = '')
    {
        if(empty($url) || empty($param)){
            return $this->return_false('请求请求参数不能为空！');
        }
        if(is_string($param)){
            $paramsStr = $param;
        } else{
            // 使用接送方式传递值
            //$paramsStr = http_build_query($param);
            //$paramsStr = mb_convert_encoding(json_encode($param, JSON_UNESCAPED_UNICODE), 'GBK', 'UTF8');
            //$paramsStr = $this->toUtf8(json_encode($param, JSON_UNESCAPED_UNICODE));
            $paramsStr = $this->toGbk(json_encode($param, JSON_UNESCAPED_UNICODE));
        }

        $token   = $this->getToken();
        $postUrl = $url;
        if(substr($url, 0, 4) != 'http'){
            $postUrl = $this->preUrl.$url;
        }
        if(strpos('?', $postUrl) !== false){
            $postUrl = $postUrl.'&access_token='.$token;
        } else{
            $postUrl = $postUrl.'?access_token='.$token;
        }

        // 初始化curl
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $postUrl);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        // 要求结果为字符串且输出到屏幕上
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        // post提交方式
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $paramsStr);

        // 运行curl
        $data = curl_exec($curl);
        curl_close($curl);
        if($data === false){
            return $this->return_false('请求未走通！');
        }

        // 重新转换成utf8编码
        //$data = mb_convert_encoding($data, 'UTF8', 'GBK');
        $data = $this->toUtf8($data);


        // 已达到打开api qps请求限制
        // Open api qps request limit reached
        $response = json_decode($data, true);

        return $response;
    }

    // 生成签名
    public function header($endPoint, $path, $json_data)
    {
        // 参数
        $credentials = ["ak" => self::$accessKey, "sk" => self::$secretAccessKey];
        $httpMethod  = "POST";
        $str_sha256  = hash('sha256', $json_data);
        $params      = [];

        // 时间
        $timestamp = new \DateTime();
        $timestamp->setTimezone(new \DateTimeZone("GMT"));
        $datetime     = $timestamp->format("Y-m-d\TH:i:s\Z");
        $datetime_gmt = $timestamp->format("D, d M Y H:i:s T");


        // 用于签名的header
        $headers = [
            "Host"                 => $endPoint,
            'x-bce-content-sha256' => $str_sha256,
            'Content-Length'       => strlen($json_data),
            'Content-Type'         => "application/json",
            'x-bce-date'           => $datetime,
        ];
        $options = ['timestamp' => $timestamp, 'headersToSign' => array('host', 'x-bce-content-sha256',),];
        $ret     = (new BaiduSign())->sign($credentials, $httpMethod, $path, $headers, $params, $options);

        // 发送短信的header
        $headers_curl = [
            'Content-Type:application/json',
            'Host:'.$endPoint,
            'x-bce-date:'.$datetime,
            'Content-Length:'.strlen($json_data),
            'x-bce-content-sha256:'.$str_sha256,
            'Authorization:'.$ret,
            "Accept-Encoding: gzip,deflate",
            'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/2008052906 Firefox/3.0',
            'Date:'.$datetime_gmt,
        ];

        return $headers_curl;
    }

    // 错误
    protected function return_false($error)
    {
        $this->error = $error;

        return false;
    }

    // 结束程序
    // 抛出异常
    protected function throwIf($condition, $msg, $code = 400)
    {
        if($condition){
            throw new \RuntimeException($msg, $code);
        }
    }


    // 转换到 uft8
    protected function toUtf8($text)
    {
        $encode = mb_detect_encoding($text, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));
        if($encode != "UTF-8"){
            $text = mb_convert_encoding($text, "UTF-8", $encode);
        }

        return $text;
    }

    // 转换到 uft8
    protected function toGbk($text)
    {
        $encode = mb_detect_encoding($text, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));
        if($encode != "GBK"){
            $text = mb_convert_encoding($text, "GBK", $encode);
        }

        return $text;
    }

    // 编码检测
    protected function isUtf8($text)
    {
        $encode = mb_detect_encoding($text, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));

        return $encode == "UTF-8" ? true : false;
    }

    // 转换编码
    protected function toEncoding($text, $coding = 'UTF-8', $form = 'GBK')
    {
        return mb_convert_encoding($text, $coding, $form);
    }
}


